/**  
 * @author renbangjie renbangjie@126.com  
 * @date 2014-11-27 上午10:45:50
 * @version V1.0  
 * <b>Copyright (c)</b> 2014医信金融信息服务（上海）有限公司-版权所有<br/>
 */
package com.yjd.comm.pay.util;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;

import com.yjd.comm.pay.model.BaoFooOrder;
import com.yjd.comm.util.FrameUtil;

/**
 * 宝付支付接口调用工具类
 * 
 * @author renbangjie renbangjie@126.com
 * @date 2014-11-27 上午10:45:50
 */
public class BaoFooUtils extends FrameUtil {

	private static final String COMMON_DATE = "yyyyMMddHHmmss";

	/**
	 * 校验签名,判断交易来源是否是宝付
	 * 
	 * @param paramMap
	 * @return boolean
	 */
	public static boolean authentication(Map<String, Object> paramMap) {
		// 解析宝付返回值
		BaoFooOrder baofoo = BaoFooUtils.parseBaoFooCallBackOrder(paramMap);
		// 生成宝付返回值的签名
		String signatrue = BaoFooUtils.generateCallBackSignature(baofoo);
		// 校验签名
		return signatrue.compareTo(baofoo.getSignature()) == 0;

	}

	/**
	 * 生成宝付返回的签名
	 * 
	 * @param order
	 * @return String
	 */
	public static String generateCallBackSignature(BaoFooOrder order) {
		BaoFooOrder config = BaoFooUtils.getConfig(); // 获取配置

		String backMark = config.getBackMark(), key = config.getKey();

		StringBuilder sb = new StringBuilder();
		sb.append("MemberID=").append(order.getMemberID()).append(backMark)
				.append("TerminalID=").append(order.getTerminalID())
				.append(backMark).append("TransID=").append(order.getTransID())
				.append(backMark).append("Result=").append(order.getResult())
				.append(backMark).append("ResultDesc=")
				.append(order.getResultDesc()).append(backMark)
				.append("FactMoney=").append(order.getFactMoney())
				.append(backMark).append("AdditionalInfo=")
				.append(order.getAdditionalInfo()).append(backMark)
				.append("SuccTime=").append(order.getSuccTime())
				.append(backMark).append("Md5Sign=").append(key);
		return DigestUtils.md5Hex(sb.toString());
	}

	/**
	 * 解析宝付返回的订单信息
	 * 
	 * @param paramMap
	 * @return BaoFooOrder
	 */
	public static BaoFooOrder parseBaoFooCallBackOrder(
			Map<String, Object> paramMap) {
		BaoFooOrder baofoo = new BaoFooOrder();
		baofoo.setMemberID((String) paramMap.get("MemberID"));// 商户号
		baofoo.setTerminalID((String) paramMap.get("TerminalID")); // 商户终端号
		baofoo.setTransID((String) paramMap.get("TransID"));// 商户流水号
		baofoo.setResult((String) paramMap.get("Result"));// 支付结果
		baofoo.setResultDesc((String) paramMap.get("ResultDesc"));// 支付结果描述
		baofoo.setFactMoney((String) paramMap.get("FactMoney")); // 实际成功金额，以分为单位
		baofoo.setAdditionalInfo((String) paramMap.get("AdditionalInfo")); // 订单附加消息
		baofoo.setSuccTime((String) paramMap.get("SuccTime")); // 支付完成时间
		baofoo.setSignature((String) paramMap.get("Md5Sign")); // MD5签名
		return baofoo;
	}

	/**
	 * 构建宝付订单对象
	 * 
	 * @param time
	 *            订单日期
	 * @param transID
	 *            交易号
	 * @param orderMoney
	 *            订单金额
	 * @param bankCode
	 *            银行编号
	 * @param productName
	 *            商品名称
	 * @return BaoFooOrder 宝付订单
	 */
	public static BaoFooOrder generateOrder(Date time, String transID,
			double orderMoney, String bankCode, String productName) {
		BaoFooOrder baofoo = BaoFooUtils.fill(time, transID, orderMoney,
				bankCode, productName);
		// 创建签名
		String signature = BaoFooUtils.generateSignature(baofoo);
		baofoo.setSignature(signature);

		return baofoo;
	}

	/**
	 * 生成签名字段
	 * 
	 * @param tradeDate
	 *            订单日期
	 * @param transID
	 *            订单号
	 * @param orderMoney
	 *            订单金额
	 * @param bankCode
	 *            银行编码
	 * @param productName
	 *            商品名称
	 * @return String 加密字符串
	 */
	public static String generateSignature(Date time, String transID,
			double orderMoney, String bankCode, String productName) {
		BaoFooOrder baofoo = BaoFooUtils.fill(time, transID, orderMoney,
				bankCode, productName);
		return BaoFooUtils.generateSignature(baofoo);
	}

	/**
	 * 生成签名字段
	 * 
	 * @param baofoo
	 * @return String
	 */
	public static String generateSignature(BaoFooOrder baofoo) {
		// 设置签名
		String mark = baofoo.getMark(), key = baofoo.getKey();
		StringBuilder sb = new StringBuilder();
		sb.append(baofoo.getMemberID()).append(mark).append(baofoo.getPayID())
				.append(mark).append(baofoo.getTradeDate()).append(mark)
				.append(baofoo.getTransID()).append(mark)
				.append(baofoo.getOrderMoney()).append(mark)
				.append(baofoo.getPageUrl()).append(mark)
				.append(baofoo.getReturnUrl()).append(mark)
				.append(baofoo.getNoticeType()).append(mark).append(key);
		return DigestUtils.md5Hex(sb.toString());
	}

	/**
	 * 填充订单一些必须的值
	 * 
	 * @param time
	 *            订单日期
	 * @param transID
	 *            交易号
	 * @param orderMoney
	 *            订单金额
	 * @param bankCode
	 *            银行编号
	 * @param productName
	 *            商品名称
	 * @return BaoFooOrder 宝付订单
	 */
	public static BaoFooOrder fill(Date time, String transID,
			double orderMoney, String bankCode, String productName) {
		BaoFooOrder baofoo = BaoFooUtils.getConfig();
		// 交易日期
		String transDate = new SimpleDateFormat(COMMON_DATE, Locale.CHINA)
				.format(time);
		baofoo.setTradeDate(transDate);
		baofoo.setTransID(baofoo.getMemberID() + "-" + transID);
		// 金额转换为分
		String fen = convertToCent(orderMoney);
		baofoo.setOrderMoney(fen);
		baofoo.setPayID(bankCode);
		baofoo.setProductName(productName);
		return baofoo;
	}

	/**
	 * 解析订单号
	 * 
	 * @param transID
	 * @return
	 * @throws Exception
	 *             Long
	 */
	public static Long getOrderID(String transID) throws Exception {
		if (StringUtils.isBlank(transID)) {
			FrameUtil.throwBaseException1("交易流水号异常");
		}
		
		//兼容旧版本的订单号
		if(!transID.contains("-")){
			BaoFooOrder baofoo = BaoFooUtils.getConfig();
			String sid = transID.replaceFirst(baofoo.getMemberID(), "");
			if(StringUtils.isBlank(sid)){
				throw new Exception("订单号异常");
			}
			return Long.valueOf(sid);
		}
		
		String temp = BaoFooUtils.getConfig().getMemberID() + "-";
		if (!transID.contains(temp)) {
			return null;
		}
		String sid = transID.replaceFirst(temp, "");
		if (StringUtils.isBlank(sid) || !NumberUtils.isNumber(sid)) {
			throw new Exception("订单号异常");
		}
		return Long.valueOf(sid);
	}

	/**
	 * 获取接口配置信息
	 * 
	 * @return BaoFooOrder
	 */
	public static BaoFooOrder getConfig() {
		// 读取配置文件中的配置
		String memberID = getConstResource("baofoo.memberID");
		String payUrl = getConstResource("baofoo.payUrl");
		String terminalID = getConstResource("baofoo.terminalID");
		String version = getConstResource("baofoo.version");
		String keyType = getConstResource("baofoo.keyType");
		String noticeType = getConstResource("baofoo.noticeType");
		String pageUrl = getConstResource("baofoo.pageUrl");
		String returnUrl = getConstResource("baofoo.returnUrl");
		String key = getConstResource("baofoo.key");
		String mark = getConstResource("baofoo.mark");
		String backMark = getConstResource("baofoo.backMark");
		String mPayUrl = getConstResource("baofoo.mobile.payUrl");
		
		
		BaoFooOrder baofoo = new BaoFooOrder();
		baofoo.setMemberID(memberID);
		baofoo.setNoticeType(noticeType);
		baofoo.setPayUrl(payUrl); //网关地址
		baofoo.setMbPayUrl(mPayUrl); //手机网关地址
		baofoo.setPageUrl(pageUrl);
		baofoo.setReturnUrl(returnUrl);
		baofoo.setTerminalID(terminalID);
		baofoo.setInterfaceVersion(version);
		baofoo.setKeyType(keyType);
		baofoo.setKey(key);
		baofoo.setMark(mark);
		baofoo.setBackMark(backMark);

		return baofoo;
	}

	/**
	 * 舍入
	 * 
	 * @param bd
	 * @return BigDecimal
	 */
	protected static BigDecimal scale(BigDecimal bd) {
		return bd.setScale(2, BigDecimal.ROUND_HALF_UP);
	}

	/**
	 * 换算成分
	 * 
	 * @param amount
	 * @return String
	 */
	protected static String convertToCent(Double amount) {
		BigDecimal scale = new BigDecimal(amount).multiply(BigDecimal
				.valueOf(100));
		return String.valueOf(scale(scale));
	}

	/**
	 * 换算成元
	 * 
	 * @param amount
	 * @return String
	 */
	protected static String convertToYuan(Double amount) {
		BigDecimal bd = new BigDecimal(amount).divide(BigDecimal.valueOf(100));
		return String.valueOf(scale(bd));
	}

}
